package com.dingreading.cloud.admin.service.impl;

import com.dingreading.cloud.admin.dto.CaCallNamesDto;
import com.dingreading.cloud.admin.dto.vo.MemberAccumulateVO;
import com.dingreading.cloud.admin.entity.CaCallNames;
import com.dingreading.cloud.admin.entity.table.CaCallNamesTableDef;
import com.dingreading.cloud.admin.mapper.CaCallNamesMapper;
import com.dingreading.cloud.admin.service.CaCallNamesService;
import com.dingreading.cloud.common.util.CustomCollectors;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.dingreading.cloud.admin.entity.table.MembersTableDef.members;


/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class CaCallNamesServiceImpl extends BaseServiceImpl<CaCallNamesMapper, CaCallNames, CaCallNamesTableDef> implements CaCallNamesService {

    @Override
    protected CaCallNamesTableDef getTable() {
        return CaCallNamesTableDef.caCallNames;
    }

    @Override
    public List<CaCallNamesDto> getLessonCallNameDtos(String storeUid, String lessonUid) {
        QueryCondition condition = table.lessonUid.eq(lessonUid);
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.studentType.asc());

        return getMapper().selectListByQueryAs(wrapper, CaCallNamesDto.class);
    }

    @Override
    public List<CaCallNames> getMemberCallListV3(
            String corpUid, String storeUid, String keyword, Integer callStatus, String beginDate, String endDate,
            String username, String projectUid, Integer status, List<Integer> callStatusList, List<Integer> hourTypeList
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(corpUid))
            condition.and(table.corpUid.eq(corpUid));
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.className.like(keyword)
                    .or(table.roomName.like(keyword))
                    .or(table.memberName.like(keyword))
                    .or(table.mob.like(keyword))
                    .or(table.productName.like(keyword))
                    .or(table.teacherName.like(keyword))
            );
        if (null != callStatus)
            condition.and(table.callStatus.eq(callStatus));
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.teachDate.between(beginDate, endDate));
        if (StringUtils.isNotBlank(projectUid))
            condition.and(table.projectUid.eq(projectUid));
        if (StringUtils.isNotBlank(username))
            condition.and(table.usernames.like("," + username + ","));
        if (null != status)
            condition.and(table.status.eq(status));
        if (CollectionUtils.isNotEmpty(callStatusList))
            condition.and(table.callStatus.in(callStatusList));
        if (CollectionUtils.isNotEmpty(hourTypeList))
            condition.and(table.hourType.in(hourTypeList));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.memberUid.asc(), table.teachDate.desc());

        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public Map<String, Long> getCntByServiceUids(String storeUid, List<String> uids) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        condition.and(table.serviceUid.in(uids));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.serviceUid, QueryMethods.count(table.id).as("cnt"))
                .where(condition)
                .groupBy(table.serviceUid);

        List<Row> rows = getMapper().selectRowsByQuery(wrapper);

        Map<String, Long> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(rows)) {
            for (Row row : rows) {
                String serviceUid = row.getString("service_uid");
                Long cnt = row.getLong("cnt");
                map.put(serviceUid, cnt);
            }
        }

        return map;
    }

    @Override
    public List<CaCallNamesDto> listByLessonUidIn(List<String> lessonUids) {
        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns, members.memberName.as("newMemberName"))
                .from(table)
                .leftJoin(members).on(table.memberUid.eq(members.uid))
                .where(CaCallNames::getLessonUid).in(lessonUids);
        return getMapper().selectListByQueryAs(wrapper, CaCallNamesDto.class);
    }

    @Override
    public List<CaCallNames> getMemberCallList(String corpUid, String beginDate, String endDate, String productName) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(corpUid))
            condition.and(table.corpUid.eq(corpUid));
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.teachDate.between(beginDate, endDate));
        if (StringUtils.isNotBlank(productName))
            condition.and(table.productName.eq(productName));
        condition.and(table.callStatus.in(1, 2));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.storeUid.asc(), table.memberUid.asc(), table.teachDate.asc());

        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public Map<List<String>, Map<String, MemberAccumulateVO>> getTotalMemberAccumulate(
            String corpUid, String storeUid, List<Integer> callStatusList, List<Integer> hourTypeList, Set<String> teacherUidList,
            String beginDate, String endDate
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(corpUid))
            condition.and(table.corpUid.eq(corpUid));
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        condition.and(table.callStatus.in(callStatusList))
                .and(table.hourType.in(hourTypeList))
                .and(table.teacherUid.in(teacherUidList));
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.teachDate.between(beginDate, endDate));

        QueryWrapper wrapper = QueryWrapper.create().select(
                        table.corpUid, table.storeUid, table.storeName, table.teacherUid, table.memberUid, table.projectUid,
                        table.teacherName, table.memberName, table.productName, QueryMethods.count(table.id).as("totalNum"))
                .from(table)
                .where(condition)
                .groupBy(table.teacherUid, table.teacherName, table.memberUid, table.projectUid)
                .orderBy(table.teacherUid.asc());

        List<MemberAccumulateVO> list = getMapper().selectListByQueryAs(wrapper, MemberAccumulateVO.class);

        // 按导读uid、导读姓名、会员uid分组，获取有序的map
        Map<List<String>, Map<String, MemberAccumulateVO>> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(list)) {
            //  定义一个函数Function，该函数将元素对象映射到一个键的集合里
            Function<MemberAccumulateVO, List<String>> compositeKey =
                    vo -> Arrays.asList(vo.getTeacherUid(), vo.getTeacherName(), vo.getMemberUid());
            // 再按服务uid分组
            map = list.stream()
                    .collect(Collectors.groupingBy(compositeKey, LinkedHashMap::new,
                            CustomCollectors.toMap(MemberAccumulateVO::getProjectUid, Function.identity())));
        }

        return map;
    }

    @Override
    public Map<List<String>, List<MemberAccumulateVO>> getMonthMemberAccumulate(
            String corpUid, String storeUid, List<Integer> callStatusList, List<Integer> hourTypeList,
            String beginDate, String endDate, List<String> storeUidList
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(corpUid))
            condition.and(table.corpUid.eq(corpUid));
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        if (CollectionUtils.isNotEmpty(storeUidList))
            condition.and(table.storeUid.in(storeUidList));
        condition.and(table.callStatus.in(callStatusList))
                .and(table.hourType.in(hourTypeList));
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.teachDate.between(beginDate, endDate));

        QueryWrapper wrapper = QueryWrapper.create().select(
                        table.corpUid, table.storeUid, table.storeName, table.teacherUid, table.memberUid, table.projectUid,
                        table.teacherName, table.memberName, table.productName, QueryMethods.count(table.id).as("monthNum"))
                .from(table)
                .where(condition)
                .groupBy(table.teacherUid, table.memberUid, table.projectUid)
                .orderBy(table.teacherUid.asc(), table.memberUid.asc());

        List<MemberAccumulateVO> list = getMapper().selectListByQueryAs(wrapper, MemberAccumulateVO.class);

        // 按导读uid、导读姓名分组，获取有序的map
        Map<List<String>, List<MemberAccumulateVO>> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(list)) {
            //  定义一个函数Function，该函数将元素对象映射到一个键的集合里
            Function<MemberAccumulateVO, List<String>> compositeKey =
                    vo -> Arrays.asList(vo.getTeacherUid(), vo.getTeacherName());

            map = list.stream().collect(Collectors.groupingBy(compositeKey, LinkedHashMap::new, Collectors.toList()));
        }

        return map;
    }

    @Override
    public List<CaCallNames> consumeListBySelfStore(List<String> storeUidList, List<Integer> hourTypeList, String beginDate, String endDate) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.in(storeUidList))
                .and(table.status.in(2))
                .and(table.callStatus.in(1, 2))
                .and(table.hourType.in(hourTypeList))
                .and(table.teachDate.between(beginDate, endDate));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.teachDate.asc());

        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public List<CaCallNames> getCallList(String corpUid, String beginDate, String endDate, List<String> projectUidList) {
        QueryCondition condition = table.corpUid.eq(corpUid)
                .and(table.teachDate.between(beginDate, endDate))
                .and(table.projectUid.in(projectUidList));

        return getMapper().selectListByCondition(condition);
    }

    @Override
    public void updateUnitAmount(String uid, double unitAmount) {
        UpdateChain.of(CaCallNames.class)
                .set(table.unitAmount, unitAmount)
                .where(table.serviceUid.eq(uid))
                .update();
    }

}
